#include <QFile>
#include <QMessageBox>

#include "NFSTexture.h"

static int log2i(int val)
{
	int ret = 0;
	while (val != 0)
	{
		val >>= 1;
		ret++;
	}
	return ret;
}

static int GetImageSizeForType(int type, int w, int h, int numMips)
{
	int size = 0;
	while (numMips)
	{
		if (type == FOURCC_DXT5)
			size += (((w + 3) >> 2) * ((h + 3) >> 2)) << 4;
		else if (type == FOURCC_DXT1)
			size += (((w + 3) >> 2) * ((h + 3) >> 2)) << 3;
		else
			size += w * h * 4;

		if (w == 1 && h == 1)
			break;
		if (w > 1)
			w >>= 1;
		if (h > 1)
			h >>= 1;

		numMips--;
	}

	return size;
}

bool CNFSTexture::IsNFSTextureSignature(const Uint8Vector& headerData)
{
	if (headerData.size() == 32)	// iOrange - seems to be...
	{
		const S_NFSTextureHeader* hdr = reinterpret_cast<const S_NFSTextureHeader *>(&headerData[0]);
		if (hdr->type == FOURCC_DXT1 || hdr->type == FOURCC_DXT5 || hdr->type == 21)
			return true;
	}

	return false;
}

bool CNFSTexture::ConvertDDS2NFS(const QString& fileName)
{
	QFile file(fileName);
	if (!file.open(QIODevice::ReadOnly))
		return false;

	DDS_HEADER ddsHdr;
	uint32 magic;
	file.read(reinterpret_cast<char *>(&magic), sizeof(magic));
	file.read(reinterpret_cast<char *>(&ddsHdr), sizeof(ddsHdr));

	S_NFSTextureHeader nfsHdr;
	ZeroMemory(&nfsHdr, sizeof(nfsHdr));

	if (ddsHdr.ddspf.dwFlags & DDS_FOURCC)
	{
		if (ddsHdr.ddspf.dwFourCC != FOURCC_DXT1 && ddsHdr.ddspf.dwFourCC != FOURCC_DXT5)
			return false;
		else
			nfsHdr.type = ddsHdr.ddspf.dwFourCC;
	}
	else if (ddsHdr.ddspf.dwFlags & DDS_RGBA)
	{
		if (ddsHdr.ddspf.dwRGBBitCount != 32)
			return false;
		else
			nfsHdr.type = 21;
	}

	nfsHdr.width = ddsHdr.dwWidth;
	nfsHdr.height = ddsHdr.dwHeight;

	nfsHdr.stuff2 = nfsHdr.stuff3 = 1;
	nfsHdr.stuff4 = 0x3000;
	nfsHdr.unknown = 1;
	nfsHdr.numMipmaps = std::max(1, (int)ddsHdr.dwMipMapCount);

	int imageDataSize = GetImageSizeForType(nfsHdr.type, nfsHdr.width, nfsHdr.height, nfsHdr.numMipmaps);

	QString newName = fileName;
	newName = newName.replace(".dds", ".nfs", Qt::CaseInsensitive);
	QFile outFile(newName);
	if (!outFile.open(QIODevice::WriteOnly))
		return false;

	const uint32 nfsoMagic = MAKEFOURCC('N', 'F', 'S', 'O');
	const uint32 fileType = NFS_FILE_TEXTURE;
	outFile.write(reinterpret_cast<const char*>(&nfsoMagic), sizeof(nfsoMagic));
	outFile.write(reinterpret_cast<const char*>(&fileType), sizeof(fileType));

	outFile.write(reinterpret_cast<const char*>(&nfsHdr), sizeof(nfsHdr));
	char* imageData = new char[imageDataSize];
	file.read(imageData, imageDataSize);
	outFile.write(imageData, imageDataSize);
	outFile.close();
	delete [] imageData;

	return true;
}





CNFSTexture::CNFSTexture()
{
}

int CNFSTexture::InitFromData(const Uint8Vector& headerData, const Uint8Vector& imageData)
{
	const S_NFSTextureHeader* hdr = reinterpret_cast<const S_NFSTextureHeader *>(&headerData[0]);
	this->ConstructHeader(hdr);
	m_Data = imageData;

	return 0;
}

int CNFSTexture::SaveAsDDS(const QString& fileName)
{
	FILE* f = fopen(fileName.toStdString().c_str(), "wb");
	if (f)
	{
		fwrite(&MAGIC_DDS, sizeof(MAGIC_DDS), 1, f);
		fwrite(&m_DDSHeader, sizeof(m_DDSHeader), 1, f);
		fwrite(&m_Data[0], m_Data.size(), 1, f);
		fflush(f);
		fclose(f);

		return TRUE;
	}

	return FALSE;
}

int CNFSTexture::GetNumComponents(void) const
{
	if (m_DDSHeader.ddspf.dwFourCC == FOURCC_DXT1)
		return 3;
	else
		return 4;
}

int CNFSTexture::GetWidth(void) const
{
	return m_DDSHeader.dwWidth;
}

int CNFSTexture::GetHeight(void) const
{
	return m_DDSHeader.dwHeight;
}

int CNFSTexture::GetDecompressedSize(void) const
{
	const int components = this->GetNumComponents();
	return m_DDSHeader.dwWidth * m_DDSHeader.dwHeight * components;
}

int CNFSTexture::Decompress(uint8* data)
{
	if (m_DDSHeader.ddspf.dwFlags == DDS_RGBA)
		memcpy(data, &m_Data[0], m_DDSHeader.dwWidth * m_DDSHeader.dwHeight * 4);//m_Data.size());
	else
		DDS_DecodeCompressedImage(data, &m_Data[0], m_DDSHeader.dwWidth, m_DDSHeader.dwHeight, m_DDSHeader.ddspf.dwFourCC);

	return this->GetDecompressedSize();
}


void CNFSTexture::ConstructHeader(const S_NFSTextureHeader* hdr)
{
	ZeroMemory(&m_DDSHeader, sizeof(m_DDSHeader));

	m_DDSHeader.dwSize			= sizeof(m_DDSHeader);
	m_DDSHeader.dwFlags			= DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_MIPMAPCOUNT;
	m_DDSHeader.dwWidth			= hdr->width;
	m_DDSHeader.dwHeight		= hdr->height;
	m_DDSHeader.dwCaps1			= DDS_TEXTURE;
	m_DDSHeader.dwMipMapCount	= hdr->numMipmaps;

	m_DDSHeader.ddspf.dwSize	= sizeof(m_DDSHeader.ddspf);

	if (hdr->type == FOURCC_DXT1 || hdr->type == FOURCC_DXT5)
	{
		m_DDSHeader.ddspf.dwFlags		= DDS_FOURCC;
		m_DDSHeader.ddspf.dwFourCC		= hdr->type;
	}
	else if (hdr->type == 21)	// iOrange - seems to be RGBA
	{
		m_DDSHeader.ddspf.dwFlags			= DDS_RGBA;
		m_DDSHeader.ddspf.dwRGBBitCount		= 32;
		m_DDSHeader.ddspf.dwRBitMask		= 0x00ff0000;
		m_DDSHeader.ddspf.dwGBitMask		= 0x0000ff00;
		m_DDSHeader.ddspf.dwBBitMask		= 0x000000ff;
		m_DDSHeader.ddspf.dwABitMask		= 0xff000000;
	}
}
